//
//  shader.cpp
//  RPG
//
//  Created by Matt Bailey on 14/03/2014.
//  Copyright (c) 2014 Matt Bailey. All rights reserved.
//

#include "shader.hpp"

void Shader::init(string _vertex, string _fragment) {
    
    vertexPath = _vertex;
    fragmentPath = _fragment;
    
    loadShaders();
    
    matrixID = glGetUniformLocation(programID, "MVP");
    textureID  = glGetUniformLocation(programID, "textureSampler");
}

void Shader::loadShaders() {
    
    string vertexSource, fragmentSource;
    
    int compileLogLength, compileStatus;
    int linkLogLength, linkStatus;
    
    cout << "Loading Shaders";
    
    // Load Vertex Shader Source
    ifstream vertexStream;
    vertexStream.open(vertexPath);
    
    if (vertexStream.is_open()) {
        string line;
        
        while(getline(vertexStream, line)) {
            vertexSource += "\n" + line;
        }
        
        vertexStream.close();
    }
    
    else {
        cout << "\n\nERROR: Cannot Open '" << vertexPath << "'" << endl;
        exit(EXIT_FAILURE);
    }
    
    // Load Fragment Shader Source
    ifstream fragmentStream;
    fragmentStream.open(fragmentPath);
    
    if (fragmentStream.is_open()) {
        string line;
        
        while(getline(fragmentStream, line)) {
            fragmentSource += "\n" + line;
        }
        
        fragmentStream.close();
    }
    
    else {
        cout << "\n\nERROR: Cannot Open '" << vertexPath << "'" << endl;
        exit(EXIT_FAILURE);
    }
    
    cout << "\t\t\t[ OK ]\nCompiling Shaders";
    
    // Compile Vertex Shader
    GLuint vertexID = glCreateShader(GL_VERTEX_SHADER);
    
    char const *vertexSourcePtr = vertexSource.c_str();
    glShaderSource(vertexID, 1, &vertexSourcePtr, 0);
    glCompileShader(vertexID);
    
    glGetShaderiv(vertexID, GL_COMPILE_STATUS, &compileStatus);
    
    if (compileStatus != GL_TRUE) {
        cout << "\n\nERROR: Vertex Shader Compiled Unsuccessfully\n";
        
        glGetShaderiv(vertexID, GL_INFO_LOG_LENGTH, &compileLogLength);
        if (compileLogLength > 1) {
            char errorLog[compileLogLength];
            
            glGetShaderInfoLog(vertexID, compileLogLength, NULL, &errorLog[0]);
            cout << errorLog;
        }
        
        exit(EXIT_FAILURE);
    }
    
    // Compile Fragment Shader
    GLuint fragmentID = glCreateShader(GL_FRAGMENT_SHADER);
    
    char const *fragmentSourcePtr = fragmentSource.c_str();
    glShaderSource(fragmentID, 1, &fragmentSourcePtr, 0);
    glCompileShader(fragmentID);
    
    glGetShaderiv(fragmentID, GL_COMPILE_STATUS, &compileStatus);
    
    if (compileStatus != GL_TRUE) {
        cout << "\n\nERROR: Fragment Shader Compiled Unsuccessfully\n";
        
        glGetShaderiv(fragmentID, GL_INFO_LOG_LENGTH, &compileLogLength);
        if (compileLogLength > 1) {
            char errorLog[compileLogLength];
            
            glGetShaderInfoLog(fragmentID, compileLogLength, NULL, &errorLog[0]);
            cout << errorLog;
        }
        
        exit(EXIT_FAILURE);
    }
    
    cout << "\t\t[ OK ]\nLinking Shaders";
    
    programID = glCreateProgram();
    
    // Attach compiled Shaders to Program
    glAttachShader(programID, vertexID);
    glAttachShader(programID, fragmentID);
    glLinkProgram(programID);
    
    glGetProgramiv(programID, GL_LINK_STATUS, &linkStatus);
    
    if (linkStatus != GL_TRUE) {
        cout << "\n\nERROR: Shader Linked Unsuccessfully\n";
        
        glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &linkLogLength);
        
        // If there were entries, fetch them and print them out
        if (linkLogLength > 1) {
            char errorLog[linkLogLength];
            glGetProgramInfoLog(programID, linkLogLength, NULL, &errorLog[0]);
            
            cout << errorLog;
        }
        
        exit(EXIT_FAILURE);
    }
    
    cout << "\t\t\t[ OK ]\n\n";

}